/*
 *  Class name: SoccerMatchCriteriaQueryBuilder.java
 *  Version: 1.0
 *  Date: 29.3.2014
 */
package cz.muni.fi.pa165.soccergamesarchive.persistencelayer.querybuilders.entity;

import cz.muni.fi.pa165.soccergamesarchive.businesslayer.dtos.SoccerMatchHeaderDTO;
import cz.muni.fi.pa165.soccergamesarchive.persistencelayer.entities.SoccerMatch;
import cz.muni.fi.pa165.soccergamesarchive.persistencelayer.querybuilders.EntityCriteriaQueryBuilder;
import java.sql.Date;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Root;

/**
 *
 * @author Michal Ďuriš
 */
public class SoccerMatchCriteriaQueryBuilder extends EntityCriteriaQueryBuilder<SoccerMatch> {

    public SoccerMatchCriteriaQueryBuilder(Class<SoccerMatch> entityClass) {
        super(entityClass);
    }

    public TypedQuery<SoccerMatchHeaderDTO> createMatchHeaderSelectCriteriaQuery(
            EntityManager entityManager,
            Map<String, Object> filterMap,
            Map<String, Boolean> orderMap) {

        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

        CriteriaQuery<SoccerMatchHeaderDTO> criteriaQuery = criteriaBuilder
                .createQuery(SoccerMatchHeaderDTO.class);

        Root<SoccerMatch> entityRoot = criteriaQuery.from(entityClass);

        Expression<Boolean> whereExpression = processFilterMap(filterMap,
                criteriaBuilder, entityRoot);

        if (whereExpression != null) {
            criteriaQuery.where(whereExpression);
        }

        List<Order> orderList = processOrderMap(orderMap, criteriaBuilder,
                entityRoot);

        if (!orderList.isEmpty()) {
            criteriaQuery.orderBy(orderList);
        }

        criteriaQuery.groupBy(entityRoot.get("matchDate").as(Date.class));

        criteriaQuery.select(criteriaBuilder.construct(
                SoccerMatchHeaderDTO.class, entityRoot
                .get("matchDate").as(Date.class)));

        return setQueryParametres(filterMap, entityManager.createQuery(
                criteriaQuery));
    }

    public TypedQuery<Date> createMatchHeaderCountCriteriaQuery(
            EntityManager entityManager, Map<String, Object> filterMap) {

        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

        CriteriaQuery<Date> countQuery = criteriaBuilder.createQuery(Date.class);

        Root<SoccerMatch> entityRoot = countQuery.from(entityClass);

        Expression<Boolean> whereExpresion = processFilterMap(filterMap,
                criteriaBuilder, entityRoot);

        if (whereExpresion != null) {
            countQuery.where(whereExpresion);
        }

        return setQueryParametres(filterMap, entityManager.createQuery(
                countQuery.select(entityRoot.get("matchDate").as(Date.class))
                .distinct(true)));
    }

    @Override
    protected Expression<Boolean> getFieldFilterExpression(String propertyName,
                                                           CriteriaBuilder criteriaBuilder,
                                                           Root<SoccerMatch> entityRoot) {

        if (propertyName == null || propertyName.isEmpty()) {
            return null;
        }

        switch (propertyName) {
            case "homeTeam":
            case "awayTeam":
                return criteriaBuilder.like(criteriaBuilder
                        .lower(entityRoot.join(propertyName).get("name").as(
                                        String.class)), criteriaBuilder
                        .parameter(String.class, propertyName));
            case "matchDate":
                return criteriaBuilder.equal(entityRoot.get("matchDate").as(
                        Date.class), criteriaBuilder.parameter(Date.class,
                                propertyName));
            default:
                return criteriaBuilder.like(criteriaBuilder.lower(entityRoot
                        .get(propertyName).as(String.class)), criteriaBuilder
                        .parameter(String.class, propertyName));
        }
    }

    @Override
    protected Expression<?> getFieldOrderExpression(String propertyName,
                                                    Root<SoccerMatch> entityRoot) {

        if (propertyName == null || propertyName.isEmpty()) {
            return null;
        }

        switch (propertyName) {
            case "homeTeam":
            case "awayTeam":
                return entityRoot.join(propertyName).get("name");
            case "matchDate":
                return entityRoot.get(propertyName).as(Date.class);
            default:
                return entityRoot.get(propertyName);
        }
    }

}
